from fastmcp import FastMCP
import sys
import os
from typing import Dict, List, Optional, Any
# Add project root directory to Python path
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, project_root)
from tools.price_tools import get_yesterday_date, get_open_prices, get_yesterday_open_and_close_price, get_latest_position, get_yesterday_profit
import json
from tools.general_tools import get_config_value,write_config_value
mcp = FastMCP("TradeTools")

@mcp.tool()
def buy(symbol: str, amount: int) -> Dict[str, Any]:
    """
    买入股票函数
    
    该函数模拟股票买入操作，包括以下步骤：
    1. 获取当前持仓和操作ID
    2. 获取当日股票开盘价
    3. 验证买入条件（现金充足）
    4. 更新持仓（增加股票数量，减少现金）
    5. 将交易记录写入 position.jsonl 文件
    
    参数:
        symbol: 股票代码，如 "AAPL"、"MSFT" 等。
        amount: 买入数量，必须为正整数，表示要买入多少股。
        
    返回:
        Dict[str, Any]:
          - 成功：返回新的持仓字典（包含股票数量和现金余额）
          - 失败：返回 {"error": 错误信息, ...} 字典
        
    抛出:
        ValueError: 当 SIGNATURE 环境变量未设置时抛出
        
    示例:
        >>> result = buy("AAPL", 10)
        >>> print(result)  # {"AAPL": 110, "MSFT": 5, "CASH": 5000.0, ...}
    """
    # 步骤1：获取环境变量和基本信息
    # 从环境变量获取签名（模型名称），用于确定数据存储路径
    signature = get_config_value("SIGNATURE")
    if signature is None:
        raise ValueError(f"BUY：SIGNATURE 环境变量未设置，当前工作目录：{os.getcwd()}")
    
    # 从环境变量获取当前交易日日期
    today_date = get_config_value("TODAY_DATE")
    
    # 步骤2：获取当前最新持仓和操作ID
    # get_latest_position 返回两个值：持仓字典和当前最大操作ID
    # 该ID用于确保每个操作有唯一标识符
    try:
        current_position, current_action_id = get_latest_position(today_date, signature)
    except Exception as e:
        print(e)
        print(current_position, current_action_id)
        print(today_date, signature)
    # 步骤3：获取当日股票开盘价
    # 使用 get_open_prices 函数获取指定股票当日开盘价
    # 如果股票代码不存在或价格数据缺失，将引发 KeyError 异常
    try:
        this_symbol_price = get_open_prices(today_date, [symbol])[f'{symbol}_price']
    except KeyError:
        # 股票代码不存在或价格数据缺失，返回错误信息
        return {"error": f"找不到股票代码 {symbol}！此操作将不被允许。", "symbol": symbol, "date": today_date}

    # 步骤4：验证买入条件
    # 计算购买所需现金：股票价格 × 购买数量
    try:
        cash_left = current_position["CASH"] - this_symbol_price * amount
    except Exception as e:
        print(current_position, "CASH", this_symbol_price, amount)

    # 检查现金余额是否足够购买
    if cash_left < 0:
        # 现金不足，返回错误信息
        return {"error": "现金不足！此操作将不被允许。", "required_cash": this_symbol_price * amount, "cash_available": current_position.get("CASH", 0), "symbol": symbol, "date": today_date}
    else:
        # 步骤5：执行买入操作，更新持仓
        # 创建当前持仓的副本，避免直接修改原始数据
        new_position = current_position.copy()
        
        # 减少现金余额
        new_position["CASH"] = cash_left
        
        # 增加股票持仓数量
        new_position[symbol] += amount
        
        # 步骤6：将交易记录写入 position.jsonl 文件
        # 构建文件路径：{project_root}/data/agent_data/{signature}/position/position.jsonl
        # 使用追加模式("a")写入新的交易记录
        # 每个操作ID递增1，确保操作序列的唯一性
        position_file_path = os.path.join(project_root, "data", "agent_data", signature, "position", "position.jsonl")
        with open(position_file_path, "a") as f:
            # 写入JSON格式的交易记录，包含日期、操作ID、交易详情和更新后的持仓
            print(
                f"正在写入 position.jsonl: {json.dumps({'date': today_date, 'id': current_action_id + 1, 'this_action': {'action': 'buy', 'symbol': symbol, 'amount': amount}, 'positions': new_position})}")
            f.write(json.dumps({"date": today_date, "id": current_action_id + 1, "this_action":{"action":"buy","symbol":symbol,"amount":amount},"positions": new_position}) + "\n")
        # 步骤7：返回更新后的持仓
        write_config_value("IF_TRADE", True)
        print("IF_TRADE", get_config_value("IF_TRADE"))
        return new_position

@mcp.tool()
def sell(symbol: str, amount: int) -> Dict[str, Any]:
    """
    卖出股票函数
    
    该函数模拟股票卖出操作，包括以下步骤：
    1. 获取当前持仓和操作ID
    2. 获取当日股票开盘价
    3. 验证卖出条件（持仓存在，数量充足）
    4. 更新持仓（减少股票数量，增加现金）
    5. 将交易记录写入 position.jsonl 文件
    
    参数:
        symbol: 股票代码，如 "AAPL"、"MSFT" 等。
        amount: 卖出数量，必须为正整数，表示要卖出多少股。
        
    返回:
        Dict[str, Any]:
          - 成功：返回新的持仓字典（包含股票数量和现金余额）
          - 失败：返回 {"error": 错误信息, ...} 字典
        
    抛出:
        ValueError: 当 SIGNATURE 环境变量未设置时抛出
        
    示例:
        >>> result = sell("AAPL", 10)
        >>> print(result)  # {"AAPL": 90, "MSFT": 5, "CASH": 15000.0, ...}
    """
    # 步骤1：获取环境变量和基本信息
    # 从环境变量获取签名（模型名称），用于确定数据存储路径
    signature = get_config_value("SIGNATURE")
    if signature is None:
        raise ValueError("SELL：SIGNATURE 环境变量未设置")
    
    # 从环境变量获取当前交易日日期
    today_date = get_config_value("TODAY_DATE")
    
    # 步骤2：获取当前最新持仓和操作ID
    # get_latest_position 返回两个值：持仓字典和当前最大操作ID
    # 该ID用于确保每个操作有唯一标识符
    current_position, current_action_id = get_latest_position(today_date, signature)
    
    # 步骤3：获取当日股票开盘价
    # 使用 get_open_prices 函数获取指定股票当日开盘价
    # 如果股票代码不存在或价格数据缺失，将引发 KeyError 异常
    try:
        this_symbol_price = get_open_prices(today_date, [symbol])[f'{symbol}_price']
    except KeyError:
        # 股票代码不存在或价格数据缺失，返回错误信息
        return {"error": f"找不到股票代码 {symbol}！此操作将不被允许。", "symbol": symbol, "date": today_date}

    # 步骤4：验证卖出条件
    # 检查是否持有该股票
    if symbol not in current_position:
        return {"error": f"没有 {symbol} 的持仓！此操作将不被允许。", "symbol": symbol, "date": today_date}

    # 检查持仓数量是否足够卖出
    if current_position[symbol] < amount:
        return {"error": "股票数量不足！此操作将不被允许。", "have": current_position.get(symbol, 0), "want_to_sell": amount, "symbol": symbol, "date": today_date}

    # 步骤5：执行卖出操作，更新持仓
    # 创建当前持仓的副本，避免直接修改原始数据
    new_position = current_position.copy()
    
    # 减少股票持仓数量
    new_position[symbol] -= amount
    
    # 增加现金余额：卖出价格 × 卖出数量
    # 使用 get 方法确保 CASH 字段存在，若不存在则默认为0
    new_position["CASH"] = new_position.get("CASH", 0) + this_symbol_price * amount

    # 步骤6：将交易记录写入 position.jsonl 文件
    # 构建文件路径：{project_root}/data/agent_data/{signature}/position/position.jsonl
    # 使用追加模式("a")写入新的交易记录
    # 每个操作ID递增1，确保操作序列的唯一性
    position_file_path = os.path.join(project_root, "data", "agent_data", signature, "position", "position.jsonl")
    with open(position_file_path, "a") as f:
        # 写入JSON格式的交易记录，包含日期、操作ID和更新后的持仓
        print(f"正在写入 position.jsonl: {json.dumps({'date': today_date, 'id': current_action_id + 1, 'this_action':{'action':'sell','symbol':symbol,'amount':amount},'positions': new_position})}")
        f.write(json.dumps({"date": today_date, "id": current_action_id + 1, "this_action":{"action":"sell","symbol":symbol,"amount":amount},"positions": new_position}) + "\n")

    # 步骤7：返回更新后的持仓
    write_config_value("IF_TRADE", True)
    return new_position

if __name__ == "__main__":
    # 以下是测试代码，已注释
    # new_result = buy("AAPL", 1)
    # print(new_result)
    # new_result = sell("AAPL", 1)
    # print(new_result)
    # 从环境变量获取端口号，如果未设置则使用默认值8002
    port = int(os.getenv("TRADE_HTTP_PORT", "8002"))
    # 运行FastMCP服务，使用streamable-http传输方式
    mcp.run(transport="streamable-http", port=port)
